package gui;

public class EditorPane extends javax.swing.JPanel {
	private static final long serialVersionUID = 1L;

	private javax.swing.JComboBox instructionList = null;
	private javax.swing.JComboBox conditionalList = null;
	private javax.swing.JTextField op1Field = null;
	private javax.swing.JTextField op2Field = null;
	private javax.swing.JComboBox op1Ops = null;
	private javax.swing.JComboBox op2Ops = null;
	
	private javax.swing.JComboBox op1Register = null;
	private javax.swing.JComboBox op1Indirect = null;
	private javax.swing.JComboBox op2Register = null;
	private javax.swing.JComboBox op2Indirect = null;

	public EditorPane(){
		super();
		this.init();
	}
	public EditorPane(core.InstructionClass i){
		super();
		this.init();
		//Put the info from the Instruction
		this.instructionList.setSelectedItem(i.inst.getGuiInstruction());
		switch(i.inst.getGuiInstruction().getCod()){
		case 0:
			break;
		case 1:
			this.op1Register.setSelectedIndex(i.r_op1);
			break;
		case 2:
			this.op1Register.setSelectedIndex(i.r_op1);
			this.op2Field.setText(java.lang.String.format("0x%04X", i.r_op2));
			break;
		case 3:
			this.op1Register.setSelectedIndex(i.r_op1);
			this.op2Register.setSelectedIndex(i.r_op2);
			break;
		case 4:
			this.op1Register.setSelectedIndex(i.r_op1);
			if(i.inst.name().endsWith("I")){
				this.op2Field.setText(java.lang.String.format("0x%04X", i.r_op2));
				this.op2Ops.setSelectedIndex(1);
			}else{
				this.op2Register.setSelectedIndex(i.r_op2);
				this.op2Ops.setSelectedIndex(0);
			}
			break;
		case 5:
			if(i.inst.name().endsWith("R")){
				this.op1Indirect.setSelectedIndex(i.r_op2);
				this.op1Ops.setSelectedIndex(0);
			}else{
				this.op1Field.setText(java.lang.String.format("0x%04X", i.r_op2));
				this.op1Ops.setSelectedIndex(1);
			}
			this.conditionalList.setSelectedItem(i.cond);
			break;
		case 6:
			switch(i.inst){
			case MOV:
				this.op1Register.setSelectedIndex(i.r_op1);
				this.op2Register.setSelectedIndex(i.r_op2);
				this.op1Ops.setSelectedIndex(0);
				this.op2Ops.setSelectedIndex(0);
				break;
			case MOVI:
				this.op1Register.setSelectedIndex(i.r_op1);
				this.op2Indirect.setSelectedIndex(i.r_op2);
				this.op1Ops.setSelectedIndex(0);
				this.op2Ops.setSelectedIndex(1);
				break;
			case IMOV:
				this.op1Indirect.setSelectedIndex(i.r_op1);
				this.op2Register.setSelectedIndex(i.r_op2);
				this.op1Ops.setSelectedIndex(1);
				this.op2Ops.setSelectedIndex(0);
				break;
			case MOVM:
				this.op1Register.setSelectedIndex(i.r_op1);
				this.op2Field.setText(java.lang.String.format("0x%04X", i.r_op2));
				this.op1Ops.setSelectedIndex(0);
				this.op2Ops.setSelectedIndex(2);
				break;
			case MMOV:
				this.op1Field.setText(java.lang.String.format("0x%04X", i.r_op2));
				this.op2Register.setSelectedIndex(i.r_op1);
				this.op1Ops.setSelectedIndex(2);
				this.op2Ops.setSelectedIndex(0);
				break;
			}
			break;
		}
	}

	private void init(){
		this.setLayout(new java.awt.GridBagLayout());
		java.awt.GridBagConstraints c;

		c = new java.awt.GridBagConstraints(0, 0, 1, 1, 0, 0, java.awt.GridBagConstraints.CENTER, java.awt.GridBagConstraints.NONE, new java.awt.Insets(10,10,10,10), 0, 0);
		this.add(this.getInstructionBox(),c);
		c = new java.awt.GridBagConstraints(1, 0, 1, 1, 0, 0, java.awt.GridBagConstraints.CENTER, java.awt.GridBagConstraints.NONE, new java.awt.Insets(10,10,10,10), 0, 0);
		this.add(this.getConditionalBox(),c);
		c = new java.awt.GridBagConstraints(0, 1, 1, 1, 0, 0, java.awt.GridBagConstraints.CENTER, java.awt.GridBagConstraints.NONE, new java.awt.Insets(10,10,10,10), 0, 0);
		this.add(this.getOp1Field(),c);
		this.add(this.getOp1Register(),c);
		this.add(this.getOp1Indirect(),c);
		c = new java.awt.GridBagConstraints(1, 1, 1, 1, 0, 0, java.awt.GridBagConstraints.CENTER, java.awt.GridBagConstraints.NONE, new java.awt.Insets(10,10,10,10), 0, 0);
		this.add(this.getOp1Box(),c);
		c = new java.awt.GridBagConstraints(0, 2, 1, 1, 0, 0, java.awt.GridBagConstraints.CENTER, java.awt.GridBagConstraints.NONE, new java.awt.Insets(10,10,10,10), 0, 0);
		this.add(this.getOp2Field(),c);
		this.add(this.getOp2Register(),c);
		this.add(this.getOp2Indirect(),c);
		c = new java.awt.GridBagConstraints(1, 2, 1, 1, 0, 0, java.awt.GridBagConstraints.CENTER, java.awt.GridBagConstraints.NONE, new java.awt.Insets(10,10,10,10), 0, 0);
		this.add(this.getOp2Box(),c);
	}

	private javax.swing.JComboBox getInstructionBox(){
		this.instructionList = new javax.swing.JComboBox(core.InstructionClass.GuiEditorInstruction.values());
		this.instructionList.addActionListener(new java.awt.event.ActionListener(){
			public void actionPerformed(java.awt.event.ActionEvent e) {
				instructionChanged();
			}
		});
		return(this.instructionList);
	}
	private javax.swing.JComboBox getConditionalBox(){
		//TODO: make these values to be more explicative (has to be a new .values() function in InstructionClass.ConditionalCodes)
		this.conditionalList = new javax.swing.JComboBox(core.InstructionClass.ConditionalCodes.values());
		this.conditionalList.addActionListener(new java.awt.event.ActionListener(){
			public void actionPerformed(java.awt.event.ActionEvent e) {
				conditionalChanged();
			}
		});
		this.conditionalList.setMinimumSize(new java.awt.Dimension(100, 25));
		this.conditionalList.setPreferredSize(new java.awt.Dimension(100, 25));
		this.conditionalList.setEnabled(false);
		return(this.conditionalList);
	}
	//For inmediate values
	private javax.swing.JTextField getOp1Field(){
		this.op1Field = new javax.swing.JTextField("", 5);
		this.op1Field.setEnabled(true);
		this.op1Field.setVisible(false);
		return(this.op1Field);
	}
	private javax.swing.JTextField getOp2Field(){
		this.op2Field = new javax.swing.JTextField("", 5);
		this.op2Field.setEnabled(true);
		this.op2Field.setVisible(false);
		return(this.op2Field);
	}
	private javax.swing.JComboBox getOp1Register(){
		java.lang.String[] ops = {"R0" , "R1", "R2", "R3", "R4", "R5", "R6", "R7", "R8", "R9", "R10" , "R11", "R12", "R13", "R14", "R15"};
		this.op1Register = new javax.swing.JComboBox(ops);
		this.op1Register.setEnabled(true);
		this.op1Register.setVisible(false);
		return(this.op1Register);
	}
	private javax.swing.JComboBox getOp2Register(){
		java.lang.String[] ops = {"R0" , "R1", "R2", "R3", "R4", "R5", "R6", "R7", "R8", "R9", "R10" , "R11", "R12", "R13", "R14", "R15"};
		this.op2Register = new javax.swing.JComboBox(ops);
		this.op2Register.setEnabled(true);
		this.op2Register.setVisible(false);
		return(this.op2Register);
	}
	private javax.swing.JComboBox getOp1Indirect(){
		java.lang.String[] ops = {"[R0]" , "[R1]", "[R2]", "[R3]", "[R4]", "[R5]", "[R6]", "[R7]", "[R8]", "[R9]", "[R10]" , "[R11]", "[R12]", "[R13]", "[R14]", "[R15]"};
		this.op1Indirect= new javax.swing.JComboBox(ops);
		this.op1Indirect.setEnabled(true);
		this.op1Indirect.setVisible(false);
		return(this.op1Indirect);
	}
	private javax.swing.JComboBox getOp2Indirect(){
		java.lang.String[] ops = {"[R0]" , "[R1]", "[R2]", "[R3]", "[R4]", "[R5]", "[R6]", "[R7]", "[R8]", "[R9]", "[R10]" , "[R11]", "[R12]", "[R13]", "[R14]", "[R15]"};
		this.op2Indirect = new javax.swing.JComboBox(ops);
		this.op2Indirect.setEnabled(true);
		this.op2Indirect.setVisible(false);
		return(this.op2Indirect);
	}
	private javax.swing.JComboBox getOp1Box(){
		java.lang.String[] ops = {"Register", "Indirect", "Inmediate"};
		this.op1Ops = new javax.swing.JComboBox(ops);
		this.op1Ops.setMinimumSize(new java.awt.Dimension(100, 25));
		this.op1Ops.setPreferredSize(new java.awt.Dimension(100, 25));
		this.op1Ops.setEnabled(false);
		this.op1Ops.addActionListener(new java.awt.event.ActionListener(){
			public void actionPerformed(java.awt.event.ActionEvent e) {
				OptBoxesLogic(1);
			}
		});
		return(this.op1Ops);
	}
	private javax.swing.JComboBox getOp2Box(){
		java.lang.String[] ops = {"Register", "Indirect", "Inmediate"};
		this.op2Ops = new javax.swing.JComboBox(ops);
		this.op2Ops.setMinimumSize(new java.awt.Dimension(100, 25));
		this.op2Ops.setPreferredSize(new java.awt.Dimension(100, 25));
		this.op2Ops.setEnabled(false);
		this.op2Ops.addActionListener(new java.awt.event.ActionListener(){
			public void actionPerformed(java.awt.event.ActionEvent e) {
				OptBoxesLogic(2);
			}
		});
		return(this.op2Ops);
	}
	private void OptBoxesLogic(int op){
		javax.swing.JComboBox aux = null;
		javax.swing.JComboBox reg = null;
		javax.swing.JComboBox ind = null;
		javax.swing.JTextField inm = null;
		if(op == 1){
			aux = this.op1Ops;
			reg = this.op1Register;
			ind = this.op1Indirect;
			inm = this.op1Field;
			core.InstructionClass.GuiEditorInstruction inst = (core.InstructionClass.GuiEditorInstruction) this.instructionList.getSelectedItem();
			if(inst == core.InstructionClass.GuiEditorInstruction.MOV){
				switch(this.op1Ops.getSelectedIndex()){
				case 0:
					this.op2Ops.setEnabled(true);
					break;
				case 1:
				case 2:
					this.op2Ops.setEnabled(false);
					this.op2Ops.setSelectedIndex(0);
					break;
				}
			}
		}else{
			aux = this.op2Ops;
			reg = this.op2Register;
			ind = this.op2Indirect;
			inm = this.op2Field;
		}
		java.lang.String auxText = (java.lang.String)aux.getSelectedItem();
		if(auxText == null){
			reg.setVisible(false);
			ind.setVisible(false);
			inm.setVisible(true);
			inm.setEditable(false);
			inm.setEnabled(false);
		}else{
			if(auxText.compareTo("Register") == 0){
				ind.setVisible(false);
				inm.setVisible(false);
				reg.setVisible(true);
			}else if(auxText.compareTo("Indirect") == 0){
				reg.setVisible(false);
				inm.setVisible(false);
				ind.setVisible(true);
			}else if(auxText.compareTo("Immediate") == 0){
				ind.setVisible(false);
				reg.setVisible(false);
				inm.setVisible(true);
				inm.setEnabled(true);
				inm.setEditable(true);
			}else{
				reg.setVisible(false);
				ind.setVisible(false);
				inm.setVisible(true);
				inm.setEditable(false);
				inm.setEnabled(false);
			}
		}
	}

	private void instructionChanged(){
		//System.out.println(this.instructionList.getSelectedItem() + " " + this.instructionList.getSelectedItem().getClass());
		core.InstructionClass.GuiEditorInstruction inst = (core.InstructionClass.GuiEditorInstruction)this.instructionList.getSelectedItem();
		switch(inst.getCod()){
		case 0: //NOP, STOP, POPSR and PUSHSR
			this.conditionalList.setEnabled(false);
			this.op1Ops.setEnabled(false);
			this.op2Ops.setEnabled(false);
			this.op1Ops.removeAllItems();
			this.op2Ops.removeAllItems();
			break;
		case 1: // INC, DEC, PUSH and POP
			this.conditionalList.setEnabled(false);
			this.op1Ops.setEnabled(false);
			this.op2Ops.setEnabled(false);
			this.op2Ops.removeAllItems();
			this.op1Ops.removeAllItems();
			this.op1Ops.insertItemAt("Register", 0);
			this.op1Ops.setSelectedIndex(0);
			break;
		case 2: //LDR, SHL, SHR
			this.conditionalList.setEnabled(false);
			this.op1Ops.setEnabled(false);
			this.op2Ops.setEnabled(false);
			this.op2Ops.removeAllItems();
			this.op1Ops.removeAllItems();
			this.op1Ops.insertItemAt("Register", 0);
			this.op2Ops.insertItemAt("Immediate", 0);
			this.op1Ops.setSelectedIndex(0);
			this.op2Ops.setSelectedIndex(0);
			break;
		case 3: //SPB, MLB, MHB, and MVN
			this.conditionalList.setEnabled(false);
			this.op1Ops.setEnabled(false);
			this.op2Ops.setEnabled(false);
			this.op2Ops.removeAllItems();
			this.op1Ops.removeAllItems();
			this.op1Ops.insertItemAt("Register", 0);
			this.op2Ops.insertItemAt("Register", 0);
			this.op1Ops.setSelectedIndex(0);
			this.op2Ops.setSelectedIndex(0);
			break;
		case 4: //Arithmetic & Logic with immediate support
			this.conditionalList.setEnabled(false);
			this.op1Ops.setEnabled(false);
			this.op2Ops.setEnabled(true);
			this.op2Ops.removeAllItems();
			this.op1Ops.removeAllItems();
			this.op1Ops.insertItemAt("Register", 0);
			this.op2Ops.insertItemAt("Register", 0);
			this.op2Ops.insertItemAt("Immediate", 1);
			this.op1Ops.setSelectedIndex(0);
			this.op2Ops.setSelectedIndex(0);
			break;
		case 5: // Jump and Call
			this.conditionalList.setEnabled(true);
			this.op1Ops.setEnabled(true);
			this.op2Ops.setEnabled(false);
			this.op2Ops.removeAllItems();
			this.op1Ops.removeAllItems();
			this.op1Ops.insertItemAt("Indirect", 0);
			this.op1Ops.insertItemAt("Immediate", 1);
			this.op1Ops.setSelectedIndex(0);
			break;
		case 6:	//Mov
			this.conditionalList.setEnabled(false);
			this.op1Ops.setEnabled(true);
			this.op2Ops.setEnabled(true);
			this.op2Ops.removeAllItems();
			this.op1Ops.removeAllItems();
			this.op1Ops.insertItemAt("Register", 0);
			this.op1Ops.insertItemAt("Indirect", 1);
			this.op1Ops.insertItemAt("Immediate", 2);
			this.op2Ops.insertItemAt("Register", 0);
			this.op2Ops.insertItemAt("Indirect", 1);
			this.op2Ops.insertItemAt("Immediate", 2);
			this.op1Ops.setSelectedIndex(0);
			this.op2Ops.setSelectedIndex(0);
			break;
		case 7: //MI, UMI
			this.conditionalList.setEnabled(false);
			this.op1Ops.setEnabled(false);
			this.op2Ops.setEnabled(false);
			this.op2Ops.removeAllItems();
			this.op1Ops.removeAllItems();
			this.op1Ops.insertItemAt("Immediate", 0);
			this.op1Ops.setSelectedIndex(0);
			break;
		}
	}
	private void conditionalChanged(){
		//System.out.println(this.conditionalList.getSelectedItem() + " " + this.conditionalList.getSelectedItem().getClass());
	}
	public java.lang.String getStringInstr(){
		java.lang.String val = null;
		java.lang.Integer auxOp1 = null;
		java.lang.Integer auxOp2 = null;

		java.lang.String op1str = null;
		java.lang.String op2str = null;

		java.lang.String Ops1 = (java.lang.String)this.op1Ops.getSelectedItem();
		java.lang.String Ops2 = (java.lang.String)this.op2Ops.getSelectedItem();

		if(Ops1 == null){
			op1str = null;
		}else if(Ops1.equals("Register")){
			op1str = (java.lang.String)this.op1Register.getSelectedItem();
		}else if(Ops1.equals("Indirect")){
			op1str = (java.lang.String)this.op1Indirect.getSelectedItem();
		}else if(Ops1.equals("Immediate")){
			try{
				auxOp1 = java.lang.Integer.decode(this.op1Field.getText());
				op1str = java.lang.String.format("0x%04X", auxOp1);
			}catch(java.lang.NumberFormatException e){
			}
		}else{
			op1str = null;
		}
		if(Ops2 == null){
			op2str = null;
		}else if(Ops2.equals("Register")){
			op2str = (java.lang.String)this.op2Register.getSelectedItem();
		}else if(Ops2.equals("Indirect")){
			op2str = (java.lang.String)this.op2Indirect.getSelectedItem();
		}else if(Ops2.equals("Immediate")){
			try{
				auxOp2 = java.lang.Integer.decode(this.op2Field.getText());
				op2str = java.lang.String.format("0x%04X", auxOp2);
			}catch(java.lang.NumberFormatException e){
			}
		}else{
			op2str = null;
		}
		//Instruction:
		core.InstructionClass.GuiEditorInstruction aux = (core.InstructionClass.GuiEditorInstruction)this.instructionList.getSelectedItem();
		switch(aux.getCod()){
		case 0://NOP, STOP, POPSR and PUSHSR
			val = aux.name();
			break;
		case 1: //INC, DEC, PUSH and POP
		case 7:
			if(op1str == null){
				this.error("You need a value for Op1");
			}else{
				val = java.lang.String.format("%s %s", aux.name(), op1str);
			}
			break;
		case 2: //LDR, SHL, SHR
		case 3: //SPB, MLB and MHB
		case 4: //Arithmetic & Logic with immediate support
		case 6: //MOV
			if(op1str == null || op2str == null){
				this.error("You need a value for Op1 and Op2");
			}else{
				if(aux == core.InstructionClass.GuiEditorInstruction.SHL || aux == core.InstructionClass.GuiEditorInstruction.SHR){
					if(auxOp2 != null){
						if((auxOp2.intValue() & 0xFFFFFFF0) != 0){
							this.error("Second argument must be in the range of [0, 15]");
						}else{
							val = java.lang.String.format("%s %s, %s", aux.name(), op1str, op2str);
						}
					}else{
						this.error("Second argument must be an integer in the range of [0, 15]");
					}
				}else{
					val = java.lang.String.format("%s %s, %s", aux.name(), op1str, op2str);
				}
			}
			break;
		case 5: //Jump and Call
			core.InstructionClass.ConditionalCodes cond = (core.InstructionClass.ConditionalCodes)this.conditionalList.getSelectedItem();
			if(op1str == null || cond == null){
				this.error("You need a value for Op1 and a Jump Condition");
			}else{
				val = java.lang.String.format("%s%s %s", aux.name(), cond.name(), op1str);
			}
			break;
		}
		return(val);
	}
	private void error(java.lang.String s){
		javax.swing.JOptionPane.showMessageDialog(this, s, "Error", javax.swing.JOptionPane.ERROR_MESSAGE);
//		javax.swing.JOptionPane.showMessageDialog(javax.swing.SwingUtilities.getWindowAncestor(this), s, "Error", javax.swing.JOptionPane.ERROR_MESSAGE);
	}
}
